package com.mf.utils;

import jakarta.annotation.Resource;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author: lmf
 * @Create: 2024/7/8 10:39
 * Description: redis 工具类
 */
@Component
public class RedisOperator {
    /**
     * 分隔符
     */
    public final String SPLIT = "&";
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    // ===============================判断值==start======================================================

    /**
     * 判断key是否存在
     */
    public boolean keyIsExist(String key) {
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }

    // ===============================判断值==end======================================================


    // ===============================设置值==start======================================================

    /**
     * 设置值，并添加过期时间
     */
    public void set(String key, String value, long timeout) {
        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }


    /**
     * 设置值，并在值上添加时间戳
     */
    public void setValueAddTimestamp(String key, String value,  long timeout) {
        // 值 + 时间戳 + 类型 +使用次数
        String str = value + SPLIT + DateUtil.getTimestamp() + SPLIT + 0;
        redisTemplate.opsForValue().set(key, str, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现命令：expire 设置过期时间，单位秒
     */
    public void expire(String key, long timeout) {
        redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现命令：setnx，设置键值对，如果键不存在，则设置键值对，如果键存在，则不设置键值对
     */
    public Boolean setIfAbsent(String key, String value, long timeout) {
        return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }


    /**
     * 根据给定的键值对执行特定的Lua脚本。
     * 该方法的目的是检查给定键的当前值是否与指定值相等，如果相等，则删除该键。
     * 使用Lua脚本的原因是，它提供了一种原子性操作的方式，确保了操作的完整性。
     * @return 返回一个整数，表示操作的结果。如果键的值与指定值相等且键被成功删除，则返回1；否则返回0。
     */
    public  Integer execute(List<String> keys, Object... args) {
        // 定义Lua脚本，该脚本检查键的值是否与给定的值相等，如果相等，则删除该键。
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        return redisTemplate.execute(new DefaultRedisScript<>(script,Integer.class) , keys,args);
    }


    // ===============================设置值==end======================================================


    // ===============================修改值==start======================================================

    /**
     * 将对应时间戳的值的使用次数+1
     */
    public void addValueUseCount(String key) {
        // 根据键获取值
        String value = get(key);
        // 检查值是否为空，如果为空则直接返回，不进行后续处理
        if (VerifyUtils.isEmpty(value)) {
            return;
        }
        // 检查值是否包含分割字符，如果包含，则进一步处理
        if (value.contains(SPLIT)) {
            // 使用分割字符将值分割成数组
            String[] split = value.split(SPLIT);
            // 检查分割后的数组长度是否为3，如果不是，则不进行后续处理
            if (split.length == 4) {
                // 提取使用次数部分并转换为整数
                int useCount = Integer.parseInt(split[2]);
                // 使用次数加1
                useCount++;
                // 重新组合值，包括原始部分、时间戳和更新后的使用次数
                String str = split[0] + SPLIT + split[1] + SPLIT + split[2] + SPLIT + useCount;
                redisTemplate.opsForValue().set(key, str);
            }
        }

    }

    // ===============================修改值==emd======================================================

    // ===============================获取值==start======================================================

    /**
     * 实现命令：GET key，返回 key所关联的字符串值。
     */
    public String get(String key) {
        return (String) redisTemplate.opsForValue().get(key);
    }

    /**
     * 获取值 hash 类型值
     */
    public BoundHashOperations<String, Object, Object> getBoundHashOperations(String key) {
       return redisTemplate.boundHashOps(key);
    }
    // ===============================获取值==end======================================================

    // ===============================删除值==start======================================================

    /**
     * 删除key
     */
    public void delete(String key) {
        redisTemplate.delete(key);
    }
    // ===============================删除值==end======================================================
}
